package com.ctrip.ec.dal;

/**
 * Created by jiang on 2018/3/22.
 */

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


/**
 * Created by jiang on 2017/2/14.
 */
public class DaoBase<Entity extends EntityBase> {
    protected DbAccess db;
    private String tableName;
    private String pkName;

    private Class<Entity> entityClazz;


    public DbAccess getDb() {
        return this.db;
    }


    public String getTableName() {
        return tableName;
    }

    public String getPkName(){
        return this.pkName;
    }

    public DaoBase(Class<Entity> clazz) {
        this(clazz, new DbAccess());
    }


    public DaoBase(Class<Entity> clazz, DbAccess db) {
        this.entityClazz = clazz;
        this.db = db;
        try {
            Entity entityClass = clazz.newInstance();
            this.pkName = entityClass.property().getPkName();
            this.tableName = entityClass.property().getTableName();
        } catch (Exception ex) {
            throw new RuntimeException("get pkname error");
        }
    }

//    private static Map<String, String> insertSqls = new HashMap<String, String>();


    private String getInsertSql(EntityBase entity) {

        boolean autoIncr = entity.add();

        EntityProperty table = entity.property();

        List<String> columes = table.getColumns();
        StringBuilder sbFields = new StringBuilder();
        StringBuilder sbValues = new StringBuilder();

        for (int i = 0; i < columes.size(); i++) {
            if (columes.get(i).equals(table.getPkName()) && autoIncr) {
                continue;
            }
            Object val = entity.fieldValue(columes.get(i));
            if (val != null) {
                sbFields.append(columes.get(i) + ",");
                sbValues.append("?" + ",");

            }
        }

        //删除最后一个逗号
        if (sbFields.charAt(sbFields.length() - 1) == ',') {
            sbFields.deleteCharAt(sbFields.length() - 1);
            sbValues.deleteCharAt(sbValues.length() - 1);
        }

        String sql = "insert into " + table.getTableName() + "(" +
                sbFields.toString() + ") values (" + sbValues.toString() + ")";

        return sql;

    }


    private String getUpdateSql(EntityBase entity) {
        StringBuilder sb = new StringBuilder();
        sb.append("update " + entity.property().getTableName() + " set ");

        List<String> columes = entity.property().getColumns();
        for (int i = 0; i < columes.size(); i++) {
            if (columes.get(i).equals(entity.property().getPkName())) {
                continue;
            }

            Object val = entity.fieldValue(columes.get(i));
            if (val != null) {
                sb.append(columes.get(i) + "=?,");
            }
        }
        //删除最后一个逗号
        if (sb.charAt(sb.length() - 1) == ',') {
            sb.deleteCharAt(sb.length() - 1);
        }

        sb.append(" where " + entity.property().getPkName() + "=?");
        return sb.toString();

    }

    public void update(Entity entity) throws SQLException {

        String sql = this.getUpdateSql(entity);
        List<String> fields = entity.property().getColumns();
        List<Object> vals = new ArrayList();
        for (String field : fields) {

            if (field.equals(entity.property().getPkName())) {
                continue;
            }
            Object val = entity.fieldValue(field);
            if (val != null) {
                vals.add(val);
            }
        }
        Object pkValue = entity.fieldValue(entity.property().getPkName());
        vals.add(pkValue);
        this.db.execute(sql, vals.toArray());
    }

    public void save(Entity entity) throws SQLException {
        if (entity.add()) {
            insert(entity);
        } else {
            update(entity);
        }
    }

    public boolean exist(String field, Object value, Long id) throws SQLException {
        String sql = "select count(*) from " + this.getTableName() + " where " + field + "=@0";
        if (id != null) {
            sql += " and id != @1";

        }
        Long count = this.db.getScalar(Long.class, sql, value, id);
        return count > 0;
    }

    public void insert(Entity entity) throws SQLException {
        String pkName = entity.property().getPkName();
        String sql = this.getInsertSql(entity);

        List<String> columes = entity.property().getColumns();

        //自增主键去掉
        List<Object> lstParas = new ArrayList<Object>(columes.size());
        for (int i = 0; i < columes.size(); i++) {
            if (columes.get(i).equals(entity.property().getPkName())) {
                continue;
            }
            Object val = entity.fieldValue(columes.get(i));
            if (val != null) {
                lstParas.add(val);
            }
        }
        Object[] vals = lstParas.toArray();

        if (entity.add() && pkName != null) { //如果自增需要把生成的id返回
            Long idvalue = 0L;
            //mysql
            try {
                if (this.db.getProvider() == DbProvider.MYSQL) {
                    this.db.execute(sql, vals);
                    idvalue = this.db.getScalar(Long.class, "select cast(last_insert_id() as signed)");
                } else {
                    sql = "SET NOCOUNT ON ; " + sql + "; select cast(SCOPE_IDENTITY() as bigint) as id; ";
                    idvalue = this.db.getScalar(Long.class, sql, vals);
                }
            } catch (SQLException ex) {
                ex.printStackTrace();
                throw ex;
            }
            if (entity.property().getPkType() == Integer.class) {
                entity.fieldValue(pkName, idvalue.intValue());
            } else {
                entity.fieldValue(pkName, idvalue);
            }

        } else {
            this.db.execute(sql, vals);
        }

    }

    public void delete(Long id) throws SQLException {

        String sql = "delete from " + this.tableName + " where " + this.pkName + "=?";

        this.db.execute(sql, id);
    }

    public void delete(Integer id) throws SQLException {
        delete(id.longValue());
    }

    public void delete(List<Long> ids) throws SQLException {
        String strIds = convert(ids);
        String sql = "delete from " + this.tableName + " where " + this.pkName + " in (" + strIds + ")";
        this.db.execute(sql);
    }

    private String convert(List<Long> ids) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < ids.size(); i++) {
            if (i == 0) {
                sb.append(ids.get(i).toString());
            } else {
                sb.append("," + ids.get(i));
            }
        }
        return sb.toString();
    }


    public List<Map<String,Object>> listAsMaps(String sqls,PagerSetting pagerSetting, Object... paras) throws SQLException {
        String sql = pagerSetting.buildPagerSql(this,paras);
        List<Map<String,Object>> list = this.db.query(sql, paras);
        return list;
    }


    public void deteteBy(String field, String value) throws SQLException {
        String sql = "delete from " + this.getTableName() + " where " + field + "=?";
        this.db.execute(sql, value);

    }


    public List<Entity> list() throws SQLException {
        String sql = "select * from " + this.tableName;
        List<Entity> list = this.db.query(entityClazz, sql);
        return list;
    }

    public List<Entity> list(String where, Object... paras) throws SQLException {
        String sql = "select * from " + this.tableName;
        if (where != null && !where.equals("")) {
            sql += " where " + where;
        }
        List<Entity> list = this.db.query(entityClazz, sql, paras);
        return list;
    }

    public List<Entity> list(PagerSetting pagerSetting, Object... paras) throws SQLException {

        String sql = pagerSetting.buildPagerSql(this,paras);

        List<Entity> list = this.db.query(entityClazz, sql, paras);
        return list;
    }

    public Entity entity(Object id) throws SQLException {


        String sql = "select * from " + this.tableName + " where " + this.pkName + "=?";

        List<Entity> list = db.query(entityClazz, sql, id);

        if (list.size() > 0) {
            return list.get(0);
        } else {
            return null;
        }
    }

    public Entity entityByCode(String code) throws SQLException {
        String sql = "select * from " + this.tableName + " where code=?";
        List<Entity> list = db.query(entityClazz, sql, code);
        if (list.size() > 0) {
            return list.get(0);
        } else {
            return null;
        }
    }



    public void erase(List<Long> ids) throws SQLException {
        if(ids != null && ids.size()>0) {
            String strIds = convert(ids);
            String sql = "update " + this.tableName + " set is_delete=1 where " + this.pkName + " in (" + strIds + ")";
            this.db.execute(sql);
        }
    }

    public void unerase(List<Long> ids) throws SQLException {
        if(ids != null && ids.size()>0) {
            String strIds = convert(ids);
            String sql = "update " + this.tableName + " set is_delete=0 where " + this.pkName + " in (" + strIds + ")";
            this.db.execute(sql);
        }
    }

    public List<Entity> listByIds(List<Long> ids) throws SQLException {
        if(ids != null && ids.size()>0){
            String strIds = convert(ids);
            String sql = "select * from " + this.getTableName() + " where id in (" + strIds+")";
            List<Entity> list = this.db.query(entityClazz,sql);
            return  list;

        }else{
            return new ArrayList<Entity>();
        }
    }
}
